/**
 * 搜索工具类
 * 支持地理编码和逆地理编码
 */

import { Map as OlMap } from 'ol';
import { Coordinate } from '../types';
import { EventEmitter } from '../utils/event';

/**
 * 搜索结果
 */
export interface SearchResult {
  /** 名称 */
  name: string;
  /** 坐标 */
  coordinate: Coordinate;
  /** 地址 */
  address?: string;
  /** 详细信息 */
  details?: Record<string, any>;
}

/**
 * 搜索配置
 */
export interface SearchOptions {
  /** 搜索服务提供商 */
  provider?: 'nominatim' | 'gaode' | 'baidu' | 'custom';
  /** 自定义搜索URL */
  searchUrl?: string;
  /** API Key（如果需要） */
  apiKey?: string;
}

/**
 * 搜索工具类
 */
export class Search extends EventEmitter {
  /** 地图实例 */
  private map: OlMap | null = null;
  /** 配置选项 */
  private options: SearchOptions;

  /**
   * 构造函数
   * @param options 配置选项
   */
  constructor(options: SearchOptions = {}) {
    super();
    this.options = {
      provider: 'nominatim',
      ...options
    };
  }

  /**
   * 初始化搜索工具
   * @param map 地图实例
   */
  init(map: OlMap): void {
    this.map = map;
  }

  /**
   * 地理编码（地址转坐标）
   * @param address 地址
   * @returns Promise<SearchResult[]>
   */
  async geocode(address: string): Promise<SearchResult[]> {
    const provider = this.options.provider || 'nominatim';

    try {
      if (provider === 'nominatim') {
        return await this.geocodeNominatim(address);
      } else if (provider === 'gaode') {
        return await this.geocodeGaode(address);
      } else if (provider === 'baidu') {
        return await this.geocodeBaidu(address);
      } else if (provider === 'custom' && this.options.searchUrl) {
        return await this.geocodeCustom(address);
      }

      throw new Error(`Unsupported provider: ${provider}`);
    } catch (error) {
      this.emit('error', error);
      throw error;
    }
  }

  /**
   * 使用 Nominatim 地理编码
   */
  private async geocodeNominatim(address: string): Promise<SearchResult[]> {
    const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}&limit=10`;
    
    const response = await fetch(url, {
      headers: {
        'User-Agent': 'zss-ol-map'
      }
    });

    if (!response.ok) {
      throw new Error(`Geocoding failed: ${response.statusText}`);
    }

    const data = await response.json();
    return data.map((item: any) => ({
      name: item.display_name,
      coordinate: [parseFloat(item.lon), parseFloat(item.lat)] as Coordinate,
      address: item.display_name,
      details: item
    }));
  }

  /**
   * 使用高德地图地理编码
   */
  private async geocodeGaode(address: string): Promise<SearchResult[]> {
    if (!this.options.apiKey) {
      throw new Error('Gaode API key is required');
    }

    const url = `https://restapi.amap.com/v3/geocode/geo?key=${this.options.apiKey}&address=${encodeURIComponent(address)}`;
    const response = await fetch(url);
    const data = await response.json();

    if (data.status !== '1') {
      throw new Error(`Geocoding failed: ${data.info}`);
    }

    return (data.geocodes || []).map((item: any) => {
      const [lng, lat] = item.location.split(',').map(parseFloat);
      return {
        name: item.formatted_address,
        coordinate: [lng, lat] as Coordinate,
        address: item.formatted_address,
        details: item
      };
    });
  }

  /**
   * 使用百度地图地理编码
   */
  private async geocodeBaidu(address: string): Promise<SearchResult[]> {
    if (!this.options.apiKey) {
      throw new Error('Baidu API key is required');
    }

    const url = `https://api.map.baidu.com/geocoding/v3/?ak=${this.options.apiKey}&address=${encodeURIComponent(address)}&output=json`;
    const response = await fetch(url);
    const data = await response.json();

    if (data.status !== 0) {
      throw new Error(`Geocoding failed: ${data.message}`);
    }

    if (!data.result || !data.result.location) {
      return [];
    }

    const { lng, lat } = data.result.location;
    return [{
      name: data.result.formatted_address || address,
      coordinate: [lng, lat] as Coordinate,
      address: data.result.formatted_address,
      details: data.result
    }];
  }

  /**
   * 自定义地理编码
   */
  private async geocodeCustom(address: string): Promise<SearchResult[]> {
    if (!this.options.searchUrl) {
      throw new Error('Custom search URL is required');
    }

    const url = this.options.searchUrl.replace('{query}', encodeURIComponent(address));
    const response = await fetch(url);
    const data = await response.json();

    // 假设返回格式为 { results: [{ name, coordinate: [lng, lat], ... }] }
    if (data.results && Array.isArray(data.results)) {
      return data.results.map((item: any) => ({
        name: item.name,
        coordinate: item.coordinate,
        address: item.address,
        details: item
      }));
    }

    return [];
  }

  /**
   * 逆地理编码（坐标转地址）
   * @param coordinate 坐标
   * @returns Promise<SearchResult>
   */
  async reverseGeocode(coordinate: Coordinate): Promise<SearchResult | null> {
    const provider = this.options.provider || 'nominatim';

    try {
      if (provider === 'nominatim') {
        return await this.reverseGeocodeNominatim(coordinate);
      } else if (provider === 'gaode') {
        return await this.reverseGeocodeGaode(coordinate);
      } else if (provider === 'baidu') {
        return await this.reverseGeocodeBaidu(coordinate);
      }

      throw new Error(`Unsupported provider: ${provider}`);
    } catch (error) {
      this.emit('error', error);
      throw error;
    }
  }

  /**
   * 使用 Nominatim 逆地理编码
   */
  private async reverseGeocodeNominatim(coordinate: Coordinate): Promise<SearchResult | null> {
    const url = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${coordinate[1]}&lon=${coordinate[0]}`;
    
    const response = await fetch(url, {
      headers: {
        'User-Agent': 'zss-ol-map'
      }
    });

    if (!response.ok) {
      throw new Error(`Reverse geocoding failed: ${response.statusText}`);
    }

    const data = await response.json();
    return {
      name: data.display_name,
      coordinate,
      address: data.display_name,
      details: data
    };
  }

  /**
   * 使用高德地图逆地理编码
   */
  private async reverseGeocodeGaode(coordinate: Coordinate): Promise<SearchResult | null> {
    if (!this.options.apiKey) {
      throw new Error('Gaode API key is required');
    }

    const url = `https://restapi.amap.com/v3/geocode/regeo?key=${this.options.apiKey}&location=${coordinate[0]},${coordinate[1]}`;
    const response = await fetch(url);
    const data = await response.json();

    if (data.status !== '1') {
      throw new Error(`Reverse geocoding failed: ${data.info}`);
    }

    const regeocode = data.regeocode;
    return {
      name: regeocode.formatted_address,
      coordinate,
      address: regeocode.formatted_address,
      details: regeocode
    };
  }

  /**
   * 使用百度地图逆地理编码
   */
  private async reverseGeocodeBaidu(coordinate: Coordinate): Promise<SearchResult | null> {
    if (!this.options.apiKey) {
      throw new Error('Baidu API key is required');
    }

    // 注意：百度地图使用 BD09 坐标系，可能需要坐标转换
    const url = `https://api.map.baidu.com/reverse_geocoding/v3/?ak=${this.options.apiKey}&output=json&coordtype=wgs84ll&location=${coordinate[1]},${coordinate[0]}`;
    const response = await fetch(url);
    const data = await response.json();

    if (data.status !== 0) {
      throw new Error(`Reverse geocoding failed: ${data.message}`);
    }

    const result = data.result;
    return {
      name: result.formatted_address,
      coordinate,
      address: result.formatted_address,
      details: result
    };
  }

  /**
   * 销毁搜索工具
   */
  destroy(): void {
    this.map = null;
    this.removeAllListeners();
    this.emit('destroy');
  }
}

